/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]

use crate::common::*;

extern "C" {
    fn sscanf(_: *const libc::c_char, _: *const libc::c_char, _: ...) -> libc::c_int;
    fn memcpy(_: *mut libc::c_void, _: *const libc::c_void, _: libc::c_ulong) -> *mut libc::c_void;
    fn memset(_: *mut libc::c_void, _: libc::c_int, _: libc::c_ulong) -> *mut libc::c_void;
    fn strspn(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_ulong;
    fn __ctype_b_loc() -> *mut *const libc::c_ushort;
    fn mktime(__tp: *mut tm) -> time_t;
    fn sudo_debug_enter_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
    );

    //多处定义，后期统一处理
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn sudo_debug_exit_time_t_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: time_t,
    );
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn get_gmtoff(clock: *mut time_t) -> libc::c_long;
    fn isdigit(c: libc::c_int) -> libc::c_int;

}

// 多处定义，后期统一处理
pub const _ISalnum: libc::c_uint = 8;
pub const _ISpunct: libc::c_uint = 4;
pub const _IScntrl: libc::c_uint = 2;
pub const _ISblank: libc::c_uint = 1;
pub const _ISgraph: libc::c_uint = 32768;
pub const _ISprint: libc::c_uint = 16384;
pub const _ISspace: libc::c_uint = 8192;
pub const _ISxdigit: libc::c_uint = 4096;
pub const _ISdigit: libc::c_uint = 2048;
pub const _ISalpha: libc::c_uint = 1024;
pub const _ISlower: libc::c_uint = 512;
pub const _ISupper: libc::c_uint = 256;

// 多处定义，后期统一处理
#[derive(Copy, Clone)]
#[repr(C)]
pub struct tm {
    pub tm_sec: libc::c_int,
    pub tm_min: libc::c_int,
    pub tm_hour: libc::c_int,
    pub tm_mday: libc::c_int,
    pub tm_mon: libc::c_int,
    pub tm_year: libc::c_int,
    pub tm_wday: libc::c_int,
    pub tm_yday: libc::c_int,
    pub tm_isdst: libc::c_int,
    pub tm_gmtoff: libc::c_long,
    pub tm_zone: *const libc::c_char,
}

/*
 * Parse a timestamp in Generalized Time format as per RFC4517.
 * E.g. yyyymmddHHMMSS.FZ or yyyymmddHHMMSS.F[+-]TZOFF
 * where minutes, seconds and fraction are optional.
 * Returns the time in Unix time format or -1 on error.
 */

#[no_mangle]
pub fn parse_gentime(mut timestr: *const libc::c_char) -> time_t {
    let mut tcopy: [libc::c_char; 17] = [0; 17];
    let mut cp: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut result: time_t = 0;
    let mut tm: tm = tm {
        tm_sec: 0,
        tm_min: 0,
        tm_hour: 0,
        tm_mday: 0,
        tm_mon: 0,
        tm_year: 0,
        tm_wday: 0,
        tm_yday: 0,
        tm_isdst: 0,
        tm_gmtoff: 0,
        tm_zone: std::ptr::null::<libc::c_char>(),
    };
    let mut len: size_t = 0;
    let mut items: libc::c_int = 0;
    let mut tzoff: libc::c_int = 0 as libc::c_int;
    let mut islocal: bool = 0 as libc::c_int != 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_PARSER!());

        /* Make a copy of the time without time zone for easy parsing. */
        len = strspn(
            timestr,
            b"0123456789.,\0" as *const u8 as *const libc::c_char,
        );
        if len >= ::core::mem::size_of::<[libc::c_char; 17]>() as libc::c_ulong {
            sudo_debug_printf!(
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                b"unable to parse general time string %s\0" as *const u8 as *const libc::c_char,
                timestr
            );

            debug_return_time_t!(-1);
        }
        memcpy(
            tcopy.as_mut_ptr() as *mut libc::c_void,
            timestr as *const libc::c_void,
            len,
        );
        tcopy[len as usize] = '\0' as i32 as libc::c_char;

        /* Parse general time, ignoring the timezone for now. */
        memset(
            &mut tm as *mut tm as *mut libc::c_void,
            0 as libc::c_int,
            ::core::mem::size_of::<tm>() as libc::c_ulong,
        );
        items = sscanf(
            tcopy.as_mut_ptr(),
            b"%4d%2d%2d%2d%2d%2d\0" as *const u8 as *const libc::c_char,
            &mut tm.tm_year as *mut libc::c_int,
            &mut tm.tm_mon as *mut libc::c_int,
            &mut tm.tm_mday as *mut libc::c_int,
            &mut tm.tm_hour as *mut libc::c_int,
            &mut tm.tm_min as *mut libc::c_int,
            &mut tm.tm_sec as *mut libc::c_int,
        );
        if items == EOF!() || items < 4 {
            sudo_debug_printf!(
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                b"only parsed %d items in general time string %s\0" as *const u8
                    as *const libc::c_char,
                items,
                timestr
            );
            debug_return_time_t!(-1);
        }
        cp = timestr.offset(((items + 1 as libc::c_int) * 2 as libc::c_int) as isize);

        /* Parse optional fractional hours/minute/second if present. */
        if (*cp.offset(0_isize) as libc::c_int == '.' as i32
            || *cp.offset(0_isize) as libc::c_int == ',' as i32)
            && isdigit(cp.offset(1 as libc::c_int as isize) as libc::c_uchar as libc::c_int)
                as libc::c_int
                != 0
        {
            let mut frac: libc::c_int =
                *cp.offset(1 as libc::c_int as isize) as libc::c_int - '0' as i32;
            match items {
                4 => {
                    /* convert fractional hour -> minutes */
                    tm.tm_min += 60 / 10 * frac;
                }
                5 => {
                    /* convert fractional minute -> seconds */
                    tm.tm_sec += 60 / 10 * frac;
                }
                _ => { /* ignore fractional second */ }
            }
            /* skip over radix and fraction */
            cp = cp.offset(2 as libc::c_int as isize);
        }
        match *cp as u8 as char {
            '-' | '+' => {
                let mut hour: libc::c_int = 0 as libc::c_int;
                let mut min: libc::c_int = 0 as libc::c_int;

                /* No DST */
                tm.tm_isdst = 0 as libc::c_int;
                /* parse time zone offset */
                items = sscanf(
                    cp.offset(1 as libc::c_int as isize),
                    b"%2d%2d\0" as *const u8 as *const libc::c_char,
                    &mut hour as *mut libc::c_int,
                    &mut min as *mut libc::c_int,
                );
                if items == EOF!() || items < 1 {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                        b"unable to parse time zone offset in %s, items %d\0" as *const u8
                            as *const libc::c_char,
                        timestr,
                        items
                    );
                    debug_return_time_t!(-1);
                }
                if *cp as libc::c_int == '-' as i32 {
                    tzoff = -(hour * 60 as libc::c_int + min) * 60 as libc::c_int;
                } else {
                    tzoff = (hour * 60 as libc::c_int + min) * 60 as libc::c_int;
                }
                cp = cp.offset((1 as libc::c_int + items * 2 as libc::c_int) as isize);
            }
            'Z' => {
                /* GMT/UTC, no DST */
                tm.tm_isdst = 0 as libc::c_int;
                cp = cp.offset(1);
            }
            '\0' => {
                /* no zone specified, use local time */
                tm.tm_isdst = -(1 as libc::c_int);
                islocal = true;
            }
            _ => {
                sudo_debug_printf!(
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                    b"unable to parse general time string %s\0" as *const u8 as *const libc::c_char,
                    timestr
                );
                debug_return_time_t!(-1);
            }
        }
        if *cp as libc::c_int != '\0' as i32 {
            sudo_debug_printf!(
                SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                b"trailing garbage in general time string %s\0" as *const u8 as *const libc::c_char,
                timestr
            );
            debug_return_time_t!(-1);
        }

        /* Adjust from Generalized Time to struct tm */
        tm.tm_year -= 1900 as libc::c_int;
        tm.tm_mon -= 1;
        result = mktime(&mut tm);
        if result != -(1 as libc::c_int) as libc::c_long && !islocal {
            /* Not local time, convert to GMT */
            result += get_gmtoff(&mut result);
            /* Adjust time based on supplied GMT offset. */
            result -= tzoff as libc::c_long;
        }

        /*if result != -(1 as libc::c_int) as libc::c_long {
            if !islocal {
                /* Not local time, convert to GMT */
                result += get_gmtoff(&mut result);
                /* Adjust time based on supplied GMT offset. */
                result -= tzoff as libc::c_long;
            }
        }*/
        debug_return_time_t!(result);
    } //unsafe
}
